#include <boost/asio.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <iostream>
#include <thread>
#include <chrono>
#include <memory>
#include <fcntl.h>
#include <unistd.h>
#include <sys/eventfd.h>
#include "debug_utils.h"

using namespace boost::asio;

/**
 * Boost.Asio 中的各种 Descriptor 类型概览
 * =====================================
 * 
 * 本示例展示了在Boost.Asio中可以用于文件描述符监控的所有主要类型
 */

namespace descriptor_demo {

// 1. POSIX Stream Descriptor - 最通用的描述符类型
class StreamDescriptorDemo {
public:
    static void demonstrate() {
        DEMO_INFO("=== POSIX Stream Descriptor 演示 ===");
        
        io_context io;
        
        // 可以包装任何支持流式I/O的文件描述符
        // 例如：管道、FIFO、套接字、设备文件等
        
        // 示例1: EventFD
        int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if (efd != -1) {
            posix::stream_descriptor eventfd_desc(io, efd);
            DEMO_INFO("EventFD 包装成功，文件描述符: {}", efd);
            
            // 可以进行异步读写操作
            auto buffer = std::make_shared<uint64_t>();
            eventfd_desc.async_read_some(
                boost::asio::buffer(buffer.get(), sizeof(*buffer)),
                [buffer](const boost::system::error_code& ec, std::size_t bytes) {
                    if (!ec) {
                        DEMO_INFO("从EventFD读取到值: {}", *buffer);
                    }
                }
            );
            
            // 写入事件
            std::thread([efd]() {
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                uint64_t value = 42;
                write(efd, &value, sizeof(value));
            }).detach();
            
            io.run_for(std::chrono::milliseconds(200));
            io.restart();
        }
        
        // 示例2: 管道 (pipe)
        int pipe_fds[2];
        if (pipe(pipe_fds) == 0) {
            posix::stream_descriptor read_end(io, pipe_fds[0]);
            // pipe_fds[1] 是写端，这里手动管理
            
            DEMO_INFO("管道包装成功，读端: {}, 写端: {}", pipe_fds[0], pipe_fds[1]);
            
            std::array<char, 64> read_buffer;
            read_end.async_read_some(
                boost::asio::buffer(read_buffer),
                [&read_buffer](const boost::system::error_code& ec, std::size_t bytes) {
                    if (!ec) {
                        std::string msg(read_buffer.data(), bytes);
                        DEMO_INFO("从管道读取到: {}", msg);
                    }
                }
            );
            
            // 写入数据到管道
            std::thread([pipe_fds]() {
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                std::string msg = "Hello Pipe!";
                write(pipe_fds[1], msg.c_str(), msg.length());
                close(pipe_fds[1]); // 关闭写端
            }).detach();
            
            io.run_for(std::chrono::milliseconds(200));
            io.restart();
        }
        
        DEMO_INFO("Stream Descriptor 演示完成\n");
    }
};

// 2. Basic Descriptor - 基础描述符类型  
class BasicDescriptorDemo {
public:
    static void demonstrate() {
        DEMO_INFO("=== Basic Descriptor 演示 ===");
        
        io_context io;
        
        // basic_descriptor 是 stream_descriptor 的基类
        // 提供更基础的文件描述符操作，主要用于等待事件
        
        int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if (efd != -1) {
            // 使用 stream_descriptor，它派生自 basic_descriptor，析构函数是公开的
            posix::stream_descriptor desc(io, efd);
            
            DEMO_INFO("Basic Descriptor 创建成功");
            
            // 使用 async_wait 等待文件描述符变为可读
            desc.async_wait(posix::descriptor_base::wait_read,
                [](const boost::system::error_code& ec) {
                    if (!ec) {
                        DEMO_INFO("文件描述符变为可读状态");
                    }
                }
            );
            
            // 触发事件
            std::thread([efd]() {
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                uint64_t value = 1;
                write(efd, &value, sizeof(value));
            }).detach();
            
            io.run_for(std::chrono::milliseconds(200));
            io.restart();
            
            // 手动关闭文件描述符
            desc.close();
        }
        
        DEMO_INFO("Basic Descriptor 演示完成\n");
    }
};

// 3. Socket - 网络套接字
class SocketDemo {
public:
    static void demonstrate() {
        DEMO_INFO("=== Socket Descriptor 演示 ===");
        
        io_context io;
        
        // TCP Socket
        ip::tcp::socket tcp_socket(io);
        DEMO_INFO("TCP Socket 创建成功");
        
        // UDP Socket  
        ip::udp::socket udp_socket(io);
        DEMO_INFO("UDP Socket 创建成功");
        
        // UNIX Domain Socket (local socket)
#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
        local::stream_protocol::socket unix_socket(io);
        DEMO_INFO("UNIX Domain Socket 创建成功");
#endif
        
        // 这些socket都可以用于异步I/O操作
        // 它们底层也是文件描述符，可以被reactor监控
        
        DEMO_INFO("Socket 演示完成\n");
    }
};

// 4. Timer - 定时器 (虽然不是文件描述符，但也可以被io_context监控)
class TimerDemo {
public:
    static void demonstrate() {
        DEMO_INFO("=== Timer 演示 ===");
        
        io_context io;
        
        // steady_timer - 基于稳定时钟的定时器
        steady_timer timer(io, std::chrono::seconds(1));
        DEMO_INFO("Steady Timer 创建成功");
        
        timer.async_wait([](const boost::system::error_code& ec) {
            if (!ec) {
                DEMO_INFO("定时器触发");
            }
        });
        
        // 在Linux上，定时器可能使用timerfd实现
        // 在其他平台上可能使用不同的机制
        
        io.run_for(std::chrono::milliseconds(1100));
        io.restart();
        
        DEMO_INFO("Timer 演示完成\n");
    }
};

#if defined(BOOST_ASIO_HAS_PIPE)
// 5. Pipe - 专门的管道类型
class PipeDemo {
public:
    static void demonstrate() {
        DEMO_INFO("=== Pipe 类型演示 ===");
        
        io_context io;
        
        // 在较新版本的Asio中，有专门的pipe类型
        // readable_pipe 和 writable_pipe
        
        // 注意：这些是较新的API，可能在某些版本中不可用
        DEMO_INFO("Asio Pipe API 需要较新版本支持");
        
        // 这里展示概念
        /*
        readable_pipe read_pipe(io);
        writable_pipe write_pipe(io);
        
        // 可以创建连接的管道对
        connect_pipe(read_pipe, write_pipe);
        */
        
        DEMO_INFO("Pipe 演示完成\n");
    }
};
#endif

#if defined(BOOST_ASIO_HAS_FILE)
// 6. File - 文件 (io_uring 支持)
class FileDemo {
public:
    static void demonstrate() {
        DEMO_INFO("=== File 类型演示 ===");
        
        // 在支持io_uring的系统上，Asio提供了file类型
        // 用于异步文件I/O操作
        
        DEMO_INFO("文件异步I/O需要io_uring支持 (Linux 5.1+)");
        
        // 示例概念:
        /*
        io_context io;
        file f(io);
        f.open("/tmp/test.txt", file_base::write_only | file_base::create);
        
        std::string data = "Hello File!";
        f.async_write_some_at(0, boost::asio::buffer(data),
            [](const boost::system::error_code& ec, std::size_t bytes) {
                // 处理写入完成
            });
        */
        
        DEMO_INFO("File 演示完成\n");
    }
};
#endif

#if defined(BOOST_ASIO_WINDOWS)
// 7. Windows Handle Types
class WindowsHandleDemo {
public:
    static void demonstrate() {
        DEMO_INFO("=== Windows Handle 类型演示 ===");
        
        // 在Windows平台上，Asio提供了各种Handle类型:
        // - stream_handle: 流式handle (类似于stream_descriptor)
        // - random_access_handle: 随机访问handle (用于文件)
        // - object_handle: 对象handle (用于等待Windows对象)
        
        /*
        io_context io;
        
        windows::stream_handle stream_h(io);
        windows::random_access_handle file_h(io);  
        windows::object_handle object_h(io);
        */
        
        DEMO_INFO("Windows Handle 类型 (仅在Windows平台可用)");
        DEMO_INFO("Windows Handle 演示完成\n");
    }
};
#endif

} // namespace descriptor_demo

// 展示descriptor在reactor中的工作原理
void demonstrate_reactor_mechanism() {
    DEMO_INFO("=== Reactor 机制演示 ===");
    
    io_context io;
    
    // 创建多个不同类型的descriptor
    int efd1 = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
    int efd2 = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
    
    posix::stream_descriptor desc1(io, efd1);
    posix::stream_descriptor desc2(io, efd2);
    
    DEMO_INFO("创建了两个EventFD描述符: {} 和 {}", efd1, efd2);
    
    // 设置异步监听
    auto buffer1 = std::make_shared<uint64_t>();
    auto buffer2 = std::make_shared<uint64_t>();
    
    desc1.async_read_some(
        boost::asio::buffer(buffer1.get(), sizeof(*buffer1)),
        [buffer1](const boost::system::error_code& ec, std::size_t bytes) {
            if (!ec) {
                DEMO_INFO("描述符1收到事件: {}", *buffer1);
            }
        }
    );
    
    desc2.async_read_some(
        boost::asio::buffer(buffer2.get(), sizeof(*buffer2)),
        [buffer2](const boost::system::error_code& ec, std::size_t bytes) {
            if (!ec) {
                DEMO_INFO("描述符2收到事件: {}", *buffer2);
            }
        }
    );
    
    // 在不同时间触发事件
    std::thread([efd1, efd2]() {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        
        uint64_t value1 = 10;
        write(efd1, &value1, sizeof(value1));
        DEMO_INFO("向描述符1写入: {}", value1);
        
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        
        uint64_t value2 = 20;
        write(efd2, &value2, sizeof(value2));
        DEMO_INFO("向描述符2写入: {}", value2);
    }).detach();
    
    // reactor会监控所有注册的文件描述符
    // 当任何一个变为可读时，相应的回调会被调用
    io.run_for(std::chrono::milliseconds(300));
    
    DEMO_INFO("Reactor 演示完成：所有文件描述符都被统一管理");
    DEMO_INFO("Linux使用epoll，BSD使用kqueue，Windows使用IOCP\n");
}

// 总结各种descriptor类型的特点
void summarize_descriptor_types() {
    DEMO_INFO("=== Descriptor 类型总结 ===");
    
    DEMO_INFO("1. posix::stream_descriptor");
    DEMO_INFO("   - 最通用的描述符包装器");
    DEMO_INFO("   - 支持读写操作");
    DEMO_INFO("   - 适用于：管道、FIFO、eventfd、设备文件等");
    
    DEMO_INFO("2. posix::basic_descriptor");
    DEMO_INFO("   - stream_descriptor的基类");
    DEMO_INFO("   - 主要用于等待操作 (async_wait)");
    DEMO_INFO("   - 更轻量级，适合只需要事件通知的场景");
    
    DEMO_INFO("3. ip::tcp::socket / ip::udp::socket");
    DEMO_INFO("   - 网络套接字，底层也是文件描述符");
    DEMO_INFO("   - 提供网络特有的操作 (connect, bind, listen等)");
    DEMO_INFO("   - 支持异步连接、读写操作");
    
    DEMO_INFO("4. local::stream_protocol::socket");
    DEMO_INFO("   - UNIX域套接字");
    DEMO_INFO("   - 用于同机进程间通信");
    DEMO_INFO("   - 比TCP套接字更高效");
    
    DEMO_INFO("5. steady_timer / system_timer");
    DEMO_INFO("   - 定时器对象");
    DEMO_INFO("   - 在Linux上可能使用timerfd实现");
    DEMO_INFO("   - 提供时间相关的异步操作");
    
#if defined(BOOST_ASIO_HAS_PIPE)
    DEMO_INFO("6. readable_pipe / writable_pipe");
    DEMO_INFO("   - 专门的管道类型 (较新版本)");
    DEMO_INFO("   - 提供类型安全的管道操作");
#endif
    
#if defined(BOOST_ASIO_HAS_FILE)
    DEMO_INFO("7. file");
    DEMO_INFO("   - 异步文件I/O (需要io_uring支持)");
    DEMO_INFO("   - Linux 5.1+ 上的高性能文件操作");
#endif
    
#if defined(BOOST_ASIO_WINDOWS)
    DEMO_INFO("8. Windows Handle类型");
    DEMO_INFO("   - stream_handle: Windows流handle");
    DEMO_INFO("   - random_access_handle: 随机访问handle");
    DEMO_INFO("   - object_handle: Windows对象handle");
#endif
    
    DEMO_INFO("\n关键要点:");
    DEMO_INFO("- 所有这些类型都可以注册到io_context中");
    DEMO_INFO("- reactor会统一监控所有注册的文件描述符");
    DEMO_INFO("- 支持多路复用：epoll(Linux), kqueue(BSD), IOCP(Windows)");
    DEMO_INFO("- 提供统一的异步编程接口");
}

int main() {
    try {
        DEMO_INFO("Boost.Asio Descriptor 类型全览");
        DEMO_INFO("===============================");
        
        // 演示各种descriptor类型
        descriptor_demo::StreamDescriptorDemo::demonstrate();
        descriptor_demo::BasicDescriptorDemo::demonstrate();
        descriptor_demo::SocketDemo::demonstrate();
        descriptor_demo::TimerDemo::demonstrate();
        
#if defined(BOOST_ASIO_HAS_PIPE)
        descriptor_demo::PipeDemo::demonstrate();
#endif

#if defined(BOOST_ASIO_HAS_FILE)
        descriptor_demo::FileDemo::demonstrate();
#endif

#if defined(BOOST_ASIO_WINDOWS)
        descriptor_demo::WindowsHandleDemo::demonstrate();
#endif
        
        // 演示reactor机制
        demonstrate_reactor_mechanism();
        
        // 总结
        summarize_descriptor_types();
        
    } catch (const std::exception& e) {
        DEMO_ERROR("错误: {}", e.what());
        return 1;
    }
    
    return 0;
}
